畫室養一位學徒,是有成本的
要給他一個位置、分他畫布跟顏料、師傅要花時間指導他
如果這位學徒,每天只做一件早就可以交給別人順手完成的小事
畫室養著他的成本,早就超過他能貢獻的價值不是他做錯了什麼,是他存在的理由,已經站不住腳了
回頭看 Day 16
當時為了解決霰彈式修改,我們把散落在三個服務裡的驗證邏輯,集中回 OrderRequest.Validate()
但在那次重構之前,其實還有一段更早的歷史
專案一開始,是先建立了一個 OrderValidationHelper 類別,把驗證邏輯包在裡面
public class OrderValidationHelper
{
public void EnsureValid(OrderRequest request)
{
request.Validate();
}
}
三個服務,仍然照著舊習慣呼叫它:
public class OrderProcessor
{
private readonly OrderValidationHelper _validationHelper;
public decimal Process(OrderRequest request)
{
_validationHelper.EnsureValid(request);
// ...原有處理邏輯...
return 0;
}
}
打開 OrderValidationHelper,它只做一件事:把呼叫轉給 request.Validate()
自己什麼邏輯都沒有
Day 16 重構的時候,我們把驗證邏輯「物歸原主」搬回了
OrderRequest,卻忘了回頭看一眼
那個原本裝著邏輯的舊房子,現在已經空了,只剩一具空殼站在那裡
三個服務,還在依賴注入裡多帶著一個 OrderValidationHelper
每個人讀到這裡,都要多花幾秒鐘搞懂:「這一層轉傳,是必要的嗎?」
答案是,不必要
解法很直接,是內聯類別 (Inline Class):把 OrderValidationHelper 僅剩的呼叫,直接攤平回呼叫端
public class OrderProcessor
{
public decimal Process(OrderRequest request)
{
request.Validate();
// ...原有處理邏輯...
return 0;
}
}
public class OrderImportService
{
public void Import(OrderRequest request)
{
request.Validate();
// ...匯入邏輯...
}
}
public class OrderEditService
{
public void Edit(OrderRequest request)
{
request.Validate();
// ...編輯邏輯...
}
}
OrderValidationHelper 整個類別,可以安全刪除
三個服務的建構子也跟著變輕,少了一個完全不需要注入的相依物件
今天的例子,是重構後的殘留物
這其實是懶惰類別最常見的成因,不是有人故意設計了一個「懶惰」的類別
是它原本很稱職,只是後來職責被搬空了
另一種常見成因,是「為未來預留」(這也是筆者我最常犯的問題):
// 為了「以後可能要串第三方物流商」而先建的殼
public class ShippingProviderAdapter
{
public void Ship(Order order) => Console.WriteLine("出貨");
}
如果那個「以後」始終沒有到來,這個類別的處境,跟今天的 OrderValidationHelper 一樣
佔著一個位置,卻交不出對得起這個位置的產出
不是所有小類別都該被刪掉,判斷的重點是:
懶惰的類別不是「小」的問題,是「小到配不上它佔用的維護成本」的問題
明天我們看另一種極端:一個類別,只會被人擠資料、自己什麼行為都不做
模組四第四站:純資料類別(Data Class)